/*
 * 05-abr-2007 
 */
package futbol.tacticas.concursantes2007.Chuky.chuky.futbolista;

import java.awt.Point;
import java.util.ArrayList;



/**
 *
 * @author Joan Crosas
 */
public class AnalizadorCamino {
	public static final int DIMENSION_X = 32;
	public static final int DIMENSION_Y = 24;
	
	private Point end;
	
	private boolean meta;
	private boolean error;
	
	private Cuadrado rejilla[][];
	
	/**
	 * 
	 */
	public AnalizadorCamino( Point start, Point end, Point[] obstaculos ) {
		rejilla = new Cuadrado[ DIMENSION_X ][ DIMENSION_Y ];
		
		for( int i = 0; i < DIMENSION_X; i++ ) {
			for( int j = 0; j < DIMENSION_Y; j++ ) {
				rejilla[i][j] = new Cuadrado( i, j );
			}
		}
		
		for( int i = 0; i < obstaculos.length; i++ ) {
			int x = ( obstaculos[i].x + 160 ) / 10;
			int y = ( obstaculos[i].y + 120 ) / 10;
			x = limiteX( x );
			y = limiteY( y );
			rejilla[x][y].setTipo( Cuadrado.TIPO_OBSTACULO );
			penalizarContiguos( x, y );
		}
		
		int xEnd = ( ( end.x + 160 ) / 10 ) -1;
		int yEnd = ( ( end.y + 120 ) / 10 ) -1;
		xEnd = limiteX( xEnd );
		yEnd = limiteY( yEnd );
		rejilla[xEnd][yEnd].setTipo( Cuadrado.TIPO_END );
		this.end = new Point( xEnd, yEnd );
		
		int xStart = ( ( start.x + 160 ) / 10 ) -1;
		int yStart = ( ( start.y + 120 ) / 10 ) -1;
		xStart = limiteX( xStart );
		yStart = limiteY( yStart );
		int disMeta = ( xEnd - xStart ) * 10 + ( Math.abs( yEnd - yStart ) * 10 );
		rejilla[xStart][yStart].setTipo( Cuadrado.TIPO_START );
		rejilla[xStart][yStart].setEstado( Cuadrado.ESTADO_ABIERTO );
		rejilla[xStart][yStart].setDistanciaMeta( disMeta );
		rejilla[xStart][yStart].setDistanciaMovimientos( 0 );
		
		meta = false;
		error = false;
		
	}
	
	private int limiteX( int x ) {
		if( x < 0 ) return 0;
		if( x > DIMENSION_X ) return DIMENSION_X;
		return x;
	}
	
	private int limiteY( int y ) {
		if( y < 0 ) return 0;
		if( y > DIMENSION_Y ) return DIMENSION_Y;
		return y;
	}
	
	private void penalizarContiguos(int i, int j) {
		for( int x = i - 2; x <= i + 2; x++ ) {
			for( int y = j - 2; y <= j + 2; y++ ) {
				if( limites( x, y ) && !obstaculo( x , y ) ) {
					int penalizacion = 300;
					if( Math.abs( x - i ) == 2 || Math.abs( y - j ) == 2 ) {
						penalizacion = 150;
					}
					rejilla[x][y].addPenalizacion( penalizacion );
				}
			}
		}
	}
	
	

	public Camino analizar() {
		Cuadrado cuadrado = null;
		while( !meta && !error ) {
			cuadrado = getMejorCuadrado();
			if( cuadrado == null ) {
				error = true;
				break;
			}
			int i = cuadrado.getPosicion().x;
			int j = cuadrado.getPosicion().y;
			for( int x = i - 1; x <= i + 1 && !meta; x++ ) {
				for( int y = j - 1; y <= j + 1 && !meta; y++ ) {
					if( limites( x, y ) && !obstaculo( x , y ) && !cerrada( x, y ) ) {
						Cuadrado cuadradoHijo = rejilla[x][y];
						int disMeta = ( end.x - x ) * 10 + ( Math.abs( end.y - y ) * 10 );
						int disMovs = cuadrado.getDistanciaMovimientos() + 10;
						
						
						if( cuadradoHijo.getEstado() == Cuadrado.ESTADO_INEXPLORADO ) {
							cuadradoHijo.setEstado( Cuadrado.ESTADO_ABIERTO );
							cuadradoHijo.setPadre( cuadrado );
							cuadradoHijo.setDistanciaMeta( disMeta );
							cuadradoHijo.setDistanciaMovimientos( disMovs );
							
							if( disMeta < 20 ) {
								meta = true;
								break;
							}
							
						} else if( cuadradoHijo.getEstado() == Cuadrado.ESTADO_ABIERTO ) {
							int coste = cuadradoHijo.getCoste();
							int nuevoCoste = disMeta + disMovs + cuadradoHijo.getPenalizacion();
							if( nuevoCoste < coste ) {
								cuadradoHijo.setPadre( cuadrado );
								cuadradoHijo.setDistanciaMeta( disMeta );
								cuadradoHijo.setDistanciaMovimientos( disMovs );
							}
						}
					}
				}
			}
		}
		
		Camino camino = null;
		
		if( cuadrado != null ) {
			int coste = cuadrado.getCoste();
			
			ArrayList<Point> listCamino = new ArrayList<Point>();
			
			Cuadrado cuadradoCamino = cuadrado;
			while( cuadradoCamino != null ) {
				listCamino.add( cuadradoCamino.getPosicion() );
				cuadradoCamino = cuadradoCamino.getPadre();
			}
			
			int size = listCamino.size();
			Point[] mejorCamino = new Point[ size ];
			for( int k = size; k > 0; k-- ) {
				int x = listCamino.get( k-1 ).x * 10 - 160;
				int y = listCamino.get( k-1 ).y * 10 - 120;
				mejorCamino[size - k] = new Point( x, y );
			}
			
			camino = new Camino( mejorCamino, coste );
		}
		
		return camino;
	}
	
	private boolean limites( int x, int y ) {
		if( x > -1 && x < DIMENSION_X && y > -1 && y < DIMENSION_Y ) {
			return true;
		}
		return false;
	}
	
	private boolean cerrada(int x, int y) {
		if( rejilla[x][y].getEstado() == Cuadrado.ESTADO_CERRADO ) {
			return true;
		}
		return false;
	}

	private boolean obstaculo(int x, int y) {
		if( rejilla[x][y].getTipo() == Cuadrado.TIPO_OBSTACULO ) {
			return true;
		}
		return false;
	}
	
	private Cuadrado getMejorCuadrado() {
		Cuadrado mejor = null;
		
		for( int i = 0; i < DIMENSION_X; i++ ) {
			for( int j = 0; j < DIMENSION_Y; j++ ) {
				
				if( rejilla[i][j].getEstado() == Cuadrado.ESTADO_ABIERTO ) { // rejilla[i][j].getTipo() != Cuadrado.TIPO_OBSTACULO &&
					if( mejor == null ) {
						mejor = rejilla[i][j];
						
						
					} else if( rejilla[i][j].getCoste() < mejor.getCoste() ) { // rejilla[i][j].getTipo() != Cuadrado.TIPO_OBSTACULO && 
						mejor = rejilla[i][j];
					}
					
				}
				
			}
		}
		mejor.setEstado( Cuadrado.ESTADO_CERRADO );
		
		return mejor;
	}
	
	
	public boolean isMeta() {
		return meta;
	}
	
	public boolean isError() {
		return error;
	}
	
	public Cuadrado[][] getRejilla() {
		return rejilla;
	}
	
}

/**
 * 
 *
 * @author Joan Crosas
 */
class Cuadrado {
	public static final int TIPO_DEFAULT = 0;
	public static final int TIPO_START = 1;
	public static final int TIPO_END = 2;
	public static final int TIPO_OBSTACULO = 3;
	
	public static final int ESTADO_INEXPLORADO = 10;
	public static final int ESTADO_ABIERTO = 11;
	public static final int ESTADO_CERRADO = 12;
	
	private Point posicion;
	private Cuadrado padre;
	
	private int tipo;
	private int penalizacion;
	private int distanciaMeta;
	private int distanciaMovimientos;
	private int estado;
	
	
	public Cuadrado( int x, int y ) {
		posicion = new Point( x, y );
		padre = null;
		
		tipo = TIPO_DEFAULT;
		penalizacion = 0;
		estado = ESTADO_INEXPLORADO;
		distanciaMeta = 0;
		distanciaMovimientos = 0;
	}
	
	/**
	 * 
	 */
	public Cuadrado( Point posicion ) {
		this.posicion = posicion;
		padre = null;
		
		tipo = TIPO_DEFAULT;
		penalizacion = 0;
		estado = ESTADO_INEXPLORADO;
		distanciaMeta = 0;
		distanciaMovimientos = 0;
		
	}


	public void setDistanciaMeta(int distanciaMeta) {
		this.distanciaMeta = distanciaMeta;
	}


	public int getDistanciaMeta() {
		return distanciaMeta;
	}

	public int getDistanciaMovimientos() {
		return distanciaMovimientos + penalizacion;
	}

	public void setDistanciaMovimientos(int distanciaMovimientos) {
		this.distanciaMovimientos = distanciaMovimientos;
	}


	public int getEstado() {
		return estado;
	}


	public void setEstado(int estado) {
		this.estado = estado;
	}


	public int getTipo() {
		return tipo;
	}


	public void setTipo(int tipo) {
		this.tipo = tipo;
	}
	
	public int getCoste() {
		return distanciaMeta + distanciaMovimientos + penalizacion;
	}


	public void addPenalizacion(int penalizacion) {
		this.penalizacion += penalizacion;
	}

	public int getPenalizacion() {
		return penalizacion;
	}

	public Cuadrado getPadre() {
		return padre;
	}


	public void setPadre(Cuadrado padre) {
		this.padre = padre;
	}


	public Point getPosicion() {
		return posicion;
	}

}
